import { goToDropPos } from "@/contrib/creep/harvester"
import { CreepRole, RoleDatas } from "@/role/types/role"
import { repairSetting } from "@/setting"
import { serializePos } from "@/utils"
import { filter, min } from "lodash"
import room from "../room"
import CreepNumberSettings from "./numberSettings"

export default class CreepController {

    // static managerCheckLinkStorageNeedToFill(creep: Creep, linkId: string): StructureLink | null {
    //     const link = Game.getObjectById(linkId) as StructureLink
    //     if (link) {
    //         if (link.store.getFreeCapacity(RESOURCE_ENERGY) > 0) {
    //             creep.log('linkStorage need to fill: ' + link.store[RESOURCE_ENERGY].toString())
    //             creep.memory.toInternalLink = true
    //             return link
    //         }
    //     }
    //     return null
    // }

    static harvesterFindSource(creep: Creep): Source | null {
        const memoryData: RoleDatas[CreepRole.Harvester] = creep.memory.data as RoleDatas[CreepRole.Harvester]
        if (!memoryData) {
            creep.log('memory error')
            return
        }

        let source
        if (!memoryData.sourceId) {
            console.log('[Harvester]' + creep.name + 'not found sourceId!!!!!!')
            return null
        }
        source = Game.getObjectById(memoryData.sourceId) as Source
        if (source) {
            if (!source.room.memory.source[source.id]['creepId']) {
                source.room.memory.source[source.id].creepId = creep.id
                creep.log('[Harvester]' + creep.name + 'bind to source' + source.id)
            }
            return source
        }
        return null
    }

    static remoteHarvesterFindRemoteSource(creep: Creep): Source | null {

        const memoryData: RoleDatas[CreepRole.RemoteHarvester] = creep.memory.data as RoleDatas[CreepRole.RemoteHarvester]
        if (!memoryData) {
            creep.log('memory error')
            return
        }

        const room = Game.rooms[memoryData.harvestRoom]
        if (!room || room.name != creep.room.name) {
            creep.goTo(new RoomPosition(25, 25, memoryData.harvestRoom))
            return null
        }
        else {
            const source = CreepController.harvesterFindSource(creep)
            if (!source) {
                if (creep.room['source']) {
                    let harvesterIndex = parseInt(creep.name.split('_')[1])
                    // 外矿特殊处理，对索引>1的2,3使用对2取模，转换成0,1
                    if (harvesterIndex > 1) {
                        harvesterIndex = harvesterIndex % 2
                    }

                    let sourceId
                    for (const id in creep.room.memory.source) {
                        if (harvesterIndex == creep.room.memory.source[id].index) {
                            sourceId = id
                        }
                    }

                    if (!sourceId || !Game.getObjectById(sourceId)) {
                        return
                    }

                    if (harvesterIndex === undefined) {
                        return
                    }
                    memoryData.sourceId = sourceId
                }
            }
            else {
                if (!source.room.memory.source[source.id].dropped) {
                    const { targetPos, range } = goToDropPos(creep, source)
                    // 没有抵达位置就准备未完成
                    if (!creep.pos.inRangeTo(targetPos, range)) return null
                    // 启动模式下，走到之后就将其设置为能量丢弃点
                    source.setDroppedPos(creep.pos)
                    // 把该位置存缓存到自己内存
                    memoryData.standPos = serializePos(creep.pos)
                    // creep.memory.data['standPos'] = serializePos(creep.pos)
                }

                if (!source.room.memory.source[source.id]['creepId']) {
                    console.log('[Harvester]', creep.name, 'bind to source', source.id)
                    source.room.memory.source[source.id].creepId = creep.id
                }
                return source
            }

            return null
        }
    }

    /**
     *
     * @param creep
     * @returns
     */
    static managerFindDropSource(creep: Creep, minEnergy: number = 400): Resource | null {
        const dropEnergy = creep.pos.findClosestByPath(FIND_DROPPED_RESOURCES, {
            filter: res => res.amount >= minEnergy
        }) as Resource
        if (dropEnergy) {
            // creep.memory.targetId = dropEnergy.id
            return dropEnergy
        }
        return null
        // }
    }

    static findTombstones(creep: Creep, minEnergy: number = 1000): Tombstone | null {
        const tombstones = creep.pos.findClosestByRange(FIND_TOMBSTONES)
        if (tombstones) {
            return tombstones
        }
        return null
    }

    static findResources(creep: Creep, minEnergy: number = 1000): Resource | null {
        const resources = creep.pos.findClosestByRange(FIND_DROPPED_RESOURCES)
        if (resources) {
            return resources
        }
        return null
    }

    static findResourceDropped(creep: Creep, minEnergy: number = 100): Resource | null {
        let resource: Resource
        creep.room['source'].forEach(source => {
            const droppedInfo = source.getDroppedInfo()
            if (droppedInfo && droppedInfo.energy) {
                resource = droppedInfo.energy as Resource
            }
        })
        if (resource) {
            if (resource.amount > minEnergy) {
                return resource
            }
        }

        // Resource
        // if

        return null
    }

    static findContainer(creep: Creep, minEnergy: number = 100): StructureContainer | null {
        const container = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_CONTAINER) && s.store[RESOURCE_ENERGY] > minEnergy } }
        ) as StructureContainer;
        if (container) {
            return container
        }
        return null
    }

    static findStorage(creep: Creep, minEnergy: number = 500): StructureStorage | null {
        const storage = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_STORAGE) && s.store[RESOURCE_ENERGY] > minEnergy } }
        ) as StructureStorage;
        if (storage) {
            return storage
        }
        return null
    }

    static findTerminal(creep: Creep, minEnergy: number = 1000): StructureTerminal | null {
        const terminal = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_TERMINAL && s.my) && s.store[RESOURCE_ENERGY] > minEnergy } }
        ) as StructureTerminal;
        if (terminal) {
            return terminal
        }
        return null
    }

    static findTerminalForLab(creep: Creep, resourceType: ResourceConstant, minEnergy: number = 0): StructureTerminal | null {
        const terminal = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_TERMINAL) && s.store[resourceType] > 0 } }
        ) as StructureTerminal;
        if (terminal) {
            return terminal
        }
        return null
    }

    static findLabEmpty(creep: Creep, resourceType: ResourceConstant): StructureLab | null {
        const lab = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_LAB) && s.store.getFreeCapacity(resourceType) > 0 } }
        ) as StructureLab;
        if (lab) {
            return lab
        }
        return null
    }

    static findLab(creep: Creep): StructureLab | null {
        const lab = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_LAB) && s.store[RESOURCE_ENERGY] > 500 && (s.store[RESOURCE_GHODIUM_ACID] > 500 || s.store[RESOURCE_GHODIUM_HYDRIDE] > 500) } }
        ) as StructureLab;
        if (lab) {
            return lab
        }
        return null
    }

    static managerFindLink(creep: Creep, minEnergy: number = 300): StructureLink | null {
        const link = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_LINK) && s.store.getFreeCapacity(RESOURCE_ENERGY) > minEnergy } }
        ) as StructureLink;
        if (link) {
            return link
        }
        return null
    }

    static managerFindTower(creep: Creep): StructureTower | null {
        const tower = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_TOWER && s.my) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
        ) as StructureTower;
        if (tower) {
            return tower
        }
        return null
    }

    static managerFindLab(creep: Creep): StructureLab | null {
        const lab = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_LAB && s.my) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
        ) as StructureLab;
        if (lab) {
            return lab
        }
        return null
    }

    /**
     * 获取能量源 container->storage
     * @param creep
     * @param minEnergy
     * @returns
     */
    static findEnergyStore(creep: Creep, minEnergy: number = 500): StructureContainer | StructureStorage | null {
        const container = CreepController.findContainer(creep, minEnergy)
        if (container) {
            return container
        }
        else {
            const storage = CreepController.findStorage(creep, minEnergy)
            if (storage) {
                return storage
            }
        }
        return null
    }

    /**
     * 外矿Link || Container
     * @param creep
     * @returns
     */
    static remoteManagerFindLinkContainer(creep: Creep): StructureWithStore | null {
        const storeObj = creep.pos.findClosestByRange(FIND_STRUCTURES, {
            filter: (s) => {
                return (
                    s.structureType == STRUCTURE_LINK ||
                    s.structureType == STRUCTURE_CONTAINER
                ) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0
            }
        }
        ) as StructureWithStore
        if (storeObj) {
            return storeObj
        }
        return null
    }

    static remoteManagerFindLinkContainerStorage(creep): StructureContainer | StructureLink | StructureStorage | null {
        const link = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_LINK) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
        ) as StructureLink
        if (link) {
            return link
        }
        else {
            const container = creep.pos.findClosestByRange(FIND_STRUCTURES,
                { filter: (s) => { return (s.structureType == STRUCTURE_CONTAINER) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
            ) as StructureContainer
            if (container) {
                return container
            }
            else {
                const storage = creep.pos.findClosestByRange(FIND_STRUCTURES,
                    { filter: (s) => { return (s.structureType == STRUCTURE_STORAGE) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
                ) as StructureStorage
                if (storage) {
                    return storage
                }
            }
        }
        return null
    }

    static managerFindExtension(creep): StructureExtension | null {
        const extension = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_EXTENSION) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
        ) as StructureExtension
        if (extension) {
            return extension
        }
        return null
    }

    static managerFindSpawnExtension(creep): StructureWithStore | null {
        const spawnExtension = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION) && s.my && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
        ) as StructureWithStore
        if (spawnExtension) {
            return spawnExtension
        }
        return null
    }

    static managerFindStorage(creep): StructureStorage | null {
        const storage = creep.pos.findClosestByRange(FIND_STRUCTURES,
            { filter: (s) => { return (s.structureType == STRUCTURE_STORAGE && s.my) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }
        ) as StructureStorage
        if (storage) {
            return storage
        }
        return null
    }
}
